fix: dedupe identical same-key markDefs on every block merge - #3195
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: fd390fc The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Bundle Stats✅ No significant changes. All scenario measurements (7)🗺️
Significant means at least 1.0 KB and 1% gzip, or at least 5 ms and 10% import time. |
cad0f5e to
4069dfe
Compare
4069dfe to
643b9ab
Compare
643b9ab to
638cde5
Compare
…g text block fragments `adjustFragmentKeys` renamed a fragment markDef whenever its `_key` existed on the destination block, on key membership alone. A def that is byte-identical to the destination's is the same annotation, so the rename churned identity for nothing: consumers that track annotations by `_key` (comments, decorations) lost the annotation they were following, and the caller's plain markDefs append then stored the same content twice under two keys. Colliding defs are now compared with `isDeepEqual`: an identical def keeps its key, is excluded from the defs appended into the destination, and its spans' `marks` stay untouched, so they resolve to the destination's copy. Same-key defs with different content rename exactly as before, pinned by a contrast test that fails when the equality branch is forced. One rider: `isDeepEqual` gains an explicit `boolean` return type. The inferred type predicate narrowed the non-equal branch of same-type comparisons to `never`, which broke compilation at the new call site.
638cde5 to
cf30d13
Compare
cf30d13 to
7fea0d4
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7fea0d4. Configure here.
`planMergeKeyRenames` carried a required `dedupeEqualMarkDefs` flag: the range-delete merge deduped identical same-key defs, but the collapsed backspace/forward-delete merges had to keep renaming them, because their `renamedBlock` feeds `insert.block`, where `parseBlock` parses the block standalone and strips any mark that does not resolve in the block's own `markDefs`: a deduped def's spans would have lost the annotation entirely. With `insert.block`'s fragment adjustment now treating identical defs as non-conflicts, that constraint is gone and the flag deletes. The planner always keeps an identical same-key def unrenamed and inside `renamedBlock.markDefs` (the block must carry the def so `parseBlock` resolves its marks) and reports it in `dedupedMarkDefKeys`; `mergeBlock` skips appending those keys. Net behavior change: the collapsed merges now dedupe. Splitting an annotated block and merging it back rejoins the annotation into one def under its original key, where it previously duplicated the def and re-keyed half the spans; the `annotations-across-blocks` gherkin scenario that pinned the old outcome under a 'possible wrong behaviour' warning now pins the rejoin, and the `unique-sibling-keys` pin of the same shape follows. Undo of a deduped merge restores both original blocks byte-identically, pinned by an undo-redo-undo round-trip. The range-delete path's behavior is unchanged.
7fea0d4 to
fd390fc
Compare

An annotation's
_keyis its identity: comments and decorations follow it, and receivers pair patches through it. Two paths treated a byte-identical markDef under the same_keyas a conflict and renamed it, churning that identity for content that is the same annotation:insert.block's fragment adjustment (which also duplicated the def through its plain markDefs append), and, forced by it, the collapsed backspace/forward-delete merges. The range-delete merge already deduped (#3187), shipping the asymmetry behind adedupeEqualMarkDefsflag.The first commit fixes the root:
adjustFragmentKeyscompares colliding defs withisDeepEqual; an identical def keeps its key, is excluded from the appended defs, and its spans' marks resolve to the destination's copy. Different-content defs rename as before, pinned by a contrast test that fails when the equality branch is forced. The second commit deletes the flag: the planner always keeps an identical def unrenamed and inside the merging block (it must stay there, sinceinsert.blockparses blocks standalone and strips marks that don't resolve in the block's ownmarkDefs), reporting it somergeBlockskips the append.The user-visible delta beyond the rename churn: splitting an annotated block and merging it back now rejoins the annotation into one def under its original key. The gherkin scenario that pinned the old duplicate-def outcome under a "possible wrong behaviour" warning now pins the rejoin. Undo of a deduped merge restores both original blocks byte-identically, pinned by an undo-redo-undo round-trip; wire-catalogue fixtures are untouched.
Note
Medium Risk
Changes core block-merge and insert.fragment key collision logic for annotations, which affects document shape, patches, and undo; behavior is well-tested but any consumer assuming renamed keys on identical defs could differ.
Overview
When two blocks share a markDef with the same
_keyand the same content, the editor no longer treats that as a key conflict and mints a new annotation id. Block merges (backspace/delete at boundaries, range-delete merges) and text fragment inserts (insert.block/ paste-into-block) now use deep equality: identical defs keep their_key, spans keep pointing at them, and duplicate defs are not appended.planMergeKeyRenamesalways dedupes equal collisions and returnsdedupedMarkDefKeysso merge callers skip re-adding those defs; the olddedupeEqualMarkDefstoggle is removed.adjustFragmentKeysapplies the same rule for fragment insertion. Different defs under the same key still get renamed as before.User-visible: split an annotated line and merge it back → one link under the original key (gherkin updated). Comments, decorations, and patch consumers that track annotation
_keyshould see less spurious renames.Reviewed by Cursor Bugbot for commit fd390fc. Bugbot is set up for automated code reviews on this repo. Configure here.